﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iNet.Tasks;

namespace iNet.Media.Imaging
{
	/// <summary>
	/// 影像解碼工作的基底類別。
	/// </summary>
	public abstract class ImageDecodeTask : MediaDecodeTask
	{
		#region 欄位
		bool _AutoRotate = true;
		IImage _DecodedImage;
		Size<int>? _DecodedPixelSize;
		int? _DecodePixelHeight;
		int? _DecodePixelWidth;
		bool _IgnoreColorProfile = false;
		ImageDecodeRequests _ImageDecodeRequests = ImageDecodeRequests.DecodeImage;
		bool _MaintainAspectRatio = true;
		bool _PreservePixelFormat = true;
		bool _UseCameraWhiteBalance = true;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 ImageDecodeTask 執行個體。
		/// </summary>
		/// <param name="decodingFormat">影像的解碼格式。</param>
		/// <exception cref="ArgumentNullException">decodingFormat 為 Null (Visual Basic 為 Nothing)。</exception>
		protected ImageDecodeTask(IMediaFormat decodingFormat)
			: base(decodingFormat)
		{ }
		/// <summary>
		/// 初始化新的 ImageDecodeTask 執行個體。
		/// </summary>
		/// <param name="decodingFormat">影像的解碼格式。</param>
		/// <param name="source">影像媒體儲存來源。</param>
		/// <param name="mediaDecodeReqs">媒體解碼請求。</param>
		/// <param name="imageDecodeReqs">影像解碼請求。</param>
		/// <exception cref="ArgumentNullException">decodingFormat 為 Null (Visual Basic 為 Nothing)。</exception>
		protected ImageDecodeTask(IMediaFormat decodingFormat, MediaStorage source, MediaDecodeRequests mediaDecodeReqs, ImageDecodeRequests imageDecodeReqs)
			: base(decodingFormat, source, mediaDecodeReqs)
		{
			_ImageDecodeRequests = imageDecodeReqs;
		}
		#endregion
		#region AutoRotate
		/// <summary>
		/// 取得或設定是否要根據中繼資料將影像轉成正確的方向，預設值為 True。
		/// </summary>
		public bool AutoRotate
		{
			get
			{
				return _AutoRotate;
			}
			set
			{
				this.SetInitializingParameter<bool>(ref _AutoRotate, value);
			}
		}
		#endregion
		#region Decode
		protected override bool Decode(TaskVersion version, MediaStorage source, MediaDecodeRequests requests)
		{
			return this.Decode(version, source, requests, _ImageDecodeRequests);
		}
		/// <summary>
		/// 解碼影像。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="source">影像儲存來源。</param>
		/// <param name="mediaDecodeReqs">媒體解碼請求。</param>
		/// <param name="imageDecodeReqs">影像解碼請求。</param>
		/// <returns>True 表示解碼完成，False 表示解碼失敗。</returns>
		protected abstract bool Decode(TaskVersion version, MediaStorage source, MediaDecodeRequests mediaDecodeReqs, ImageDecodeRequests imageDecodeReqs);
		#endregion
		#region DecodedImage
		/// <summary>
		/// 取得已解碼的影像。
		/// </summary>
		public IImage DecodedImage
		{
			get
			{
				return _DecodedImage;
			}
		}
		#endregion
		#region DecodedPixelSize
		/// <summary>
		/// 取得已解碼的像素大小。
		/// </summary>
		public Size<int>? DecodedPixelSize
		{
			get
			{
				return _DecodedPixelSize;
			}
		}
		#endregion
		#region DecodePixelHeight
		/// <summary>
		/// 取得或設定解碼的像素高度，Null (Visual Basic 為 Nothing) 表示解碼完整影像高度 -或- 根據 DecodePixelWidth 屬性計算等比例的高度。
		/// </summary>
		public int? DecodePixelHeight
		{
			get
			{
				return _DecodePixelHeight;
			}
			set
			{
				//確認參數
				if (value != null && (double.IsNaN(value.Value) || value < 0))
					throw new ArgumentOutOfRangeException();

				//設定參數
				this.SetInitializingParameter<int?>(ref _DecodePixelHeight, value);
			}
		}
		#endregion
		#region DecodePixelWidth
		/// <summary>
		/// 取得或設定解碼的像素寬度，Null (Visual Basic 為 Nothing) 表示解碼完整影像寬度 -或- 根據 DecodePixelHeight 屬性計算等比例的寬度。
		/// </summary>
		public int? DecodePixelWidth
		{
			get
			{
				return _DecodePixelWidth;
			}
			set
			{
				//確認參數
				if (value != null && (double.IsNaN(value.Value) || value < 0))
					throw new ArgumentOutOfRangeException();

				//設定參數
				this.SetInitializingParameter<int?>(ref _DecodePixelWidth, value);
			}
		}
		#endregion
		#region ExecuteChildDecodeTask
		/// <summary>
		/// 使用指定的影像解碼子工作進行解碼。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="decodeTask">指定的影像解碼子工作。</param>
		/// <param name="forwardDecodedResults">是否要將子工作的解碼結果直接作為此工作的解碼結果，預設值為 True。</param>
		/// <param name="forwardMessages">是否要將子工作產生的訊息直接向外發送，預設值為 True。</param>
		/// <returns>子工作執行結果。</returns>
		/// <exception cref="ArgumentException">decodeTask 為工作本身。</exception>
		/// <exception cref="ArgumentNullException">version 或 decodeTask 為 Null (Visual Basic 為 Nothing)。</exception>
		protected TaskState ExecuteChildDecodeTask(TaskVersion version, ImageDecodeTask decodeTask, bool forwardDecodedResults = true, bool forwardMessages = true)
		{
			//確認參數
			if (version == null)
				throw new ArgumentNullException("version");
			if (decodeTask == null)
				throw new ArgumentNullException("decodeTask");
			if (decodeTask == this)
				throw new ArgumentException();
			
			//準備事件處理方法
			EventHandler<DataEventArgs<IImage>> imageDecodedHandler = null;
			EventHandler<DataEventArgs<IMetadata>> metadataDecodedHandler = null;
			EventHandler<DataEventArgs<Size<int>>> pixelSizeDecodedHandler = null;
			EventHandler<DataEventArgs<IImage>> thumbDecodedHandler = null;
			if (forwardDecodedResults)
			{
				imageDecodedHandler = (sender, e) =>
				{
					this.SetDecodedImage(version, e.Data);
				};
				metadataDecodedHandler = (sender, e) =>
				{
					this.SetDecodedMetadata(version, e.Data);
				};
				pixelSizeDecodedHandler = (sender, e) =>
				{
					this.SetDecodedPixelSize(version, e.Data);
				};
				thumbDecodedHandler = (sender, e) =>
				{
					this.SetDecodedThumbnailImage(version, e.Data);
				};
				decodeTask.ImageDecoded += imageDecodedHandler;
				decodeTask.MetadataDecoded += metadataDecodedHandler;
				decodeTask.PixelSizeDecoded += pixelSizeDecodedHandler;
				decodeTask.ThumbnailImageDecoded += thumbDecodedHandler;
			}

			//解碼影像
			try
			{
				decodeTask.AutoRotate = _AutoRotate;
				decodeTask.DecodePixelHeight = _DecodePixelHeight;
				decodeTask.DecodePixelWidth = _DecodePixelWidth;
				decodeTask.IgnoreColorProfile = _IgnoreColorProfile;
				decodeTask.ImageDecodeRequests = _ImageDecodeRequests;
				decodeTask.MediaDecodeRequests = this.MediaDecodeRequests;
				decodeTask.PreservePixelFormat = _PreservePixelFormat;
				decodeTask.UseCameraWhiteBalance = _UseCameraWhiteBalance;
				return this.ExecuteChildTask(version, decodeTask, forwardMessages);
			}
			finally
			{
				if (forwardDecodedResults)
				{
					decodeTask.ImageDecoded -= imageDecodedHandler;
					decodeTask.MetadataDecoded -= metadataDecodedHandler;
					decodeTask.PixelSizeDecoded -= pixelSizeDecodedHandler;
					decodeTask.ThumbnailImageDecoded -= thumbDecodedHandler;
				}
			}
		}
		#endregion
		#region IgnoreColorProfile
		/// <summary>
		/// 取得或設定是否忽略內嵌於檔案中的色彩設定，預設值為 False。
		/// </summary>
		public bool IgnoreColorProfile
		{
			get
			{
				return _IgnoreColorProfile;
			}
			set
			{
				this.SetInitializingParameter<bool>(ref _IgnoreColorProfile, value);
			}
		}
		#endregion
		#region ImageDecodeRequests
		/// <summary>
		/// 取得或設定影像解碼請求組合。
		/// </summary>
		public ImageDecodeRequests ImageDecodeRequests
		{
			get
			{
				return _ImageDecodeRequests;
			}
			set
			{
				this.SetInitializingParameter<ImageDecodeRequests>(ref _ImageDecodeRequests, value);
			}
		}
		#endregion
		#region MaintainAspectRatio
		/// <summary>
		/// 取得或設定載入影像時是否維持原有的長寬比例，預設值為 True。
		/// </summary>
		public bool MaintainAspectRatio
		{
			get
			{
				return _MaintainAspectRatio;
			}
			set
			{
				this.SetInitializingParameter<bool>(ref _MaintainAspectRatio, value);
			}
		}
		#endregion
		#region PreservePixelFormat
		/// <summary>
		/// 取得或設定解碼時是否須保留原始的像素格式，預設值為 True。
		/// </summary>
		public bool PreservePixelFormat
		{
			get
			{
				return _PreservePixelFormat;
			}
			set
			{
				this.SetInitializingParameter<bool>(ref _PreservePixelFormat, value);
			}
		}
		#endregion
		#region ResetOverride
		/// <summary>
		/// 重設工作狀態。
		/// </summary>
		protected override void ResetOverride()
		{
			//呼叫基底
			base.ResetOverride();

			//重設欄位
			_DecodedImage = null;
			_DecodedPixelSize = null;
		}
		#endregion
		#region SetDecodedImage
		/// <summary>
		/// 設定已解碼的影像。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="image">已解碼的影像。</param>
		/// <exception cref="ArgumentNullException">version 為 Null (Visual Basic 為 Nothing)。</exception>
		protected void SetDecodedImage(TaskVersion version, IImage image)
		{
			//儲存結果
			this.WriteValue<IImage>(version, ref _DecodedImage, image);

			//引發事件
			if (image != null)
				this.RaiseEvent<DataEventArgs<IImage>>(version, this.ImageDecoded, new DataEventArgs<IImage>(image));
		}
		#endregion
		#region SetDecodedPixelSize
		/// <summary>
		/// 設定已解碼的影像像素大小。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="pixelSize">影像像素大小。</param>
		/// <exception cref="ArgumentNullException">version 為 Null (Visual Basic 為 Nothing)。</exception>
		protected void SetDecodedPixelSize(TaskVersion version, Size<int> pixelSize)
		{
			//儲存結果
			this.WriteValue<Size<int>?>(version, ref _DecodedPixelSize, pixelSize);

			//引發事件
			this.RaiseEvent<DataEventArgs<Size<int>>>(version, this.PixelSizeDecoded, new DataEventArgs<Size<int>>(pixelSize));
		}
		#endregion
		#region SupportedImageDecodeRequests
		/// <summary>
		/// 取得支援的影像解碼請求組合。
		/// </summary>
		public virtual ImageDecodeRequests SupportedImageDecodeRequests
		{
			get
			{
				return Imaging.ImageDecodeRequests.DecodeImage | Imaging.ImageDecodeRequests.DecodePixelSize;
			}
		}
		#endregion
		#region UseCameraWhiteBalance
		/// <summary>
		/// 取得或設定解碼時是否套用相機的白平衡設定，預設值為 True。
		/// </summary>
		public bool UseCameraWhiteBalance
		{
			get
			{
				return _UseCameraWhiteBalance;
			}
			set
			{
				this.SetInitializingParameter<bool>(ref _UseCameraWhiteBalance, value);
			}
		}
		#endregion
		#region 事件
		/// <summary>
		/// 發生在影像解碼完成後。
		/// </summary>
		public event EventHandler<DataEventArgs<IImage>> ImageDecoded;
		/// <summary>
		/// 發生在像素大小解碼完成後。
		/// </summary>
		public event EventHandler<DataEventArgs<Size<int>>> PixelSizeDecoded;
		#endregion
	}
	#region ImageDecodeRequests
	/// <summary>
	/// 表示影像解碼的工作請求。
	/// </summary>
	[Flags]
	public enum ImageDecodeRequests
	{
		/// <summary>
		/// 全部請求。
		/// </summary>
		All = (DecodeImage | DecodePixelSize),
		/// <summary>
		/// 解碼影像。
		/// </summary>
		DecodeImage = 0x1,
		/// <summary>
		/// 解碼影像像素大小。
		/// </summary>
		DecodePixelSize = 0x2,
	}
	#endregion
}
